﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CANHelper
{
    public partial class Form1 : Form
    {
        public bool isOpen;
        private uint m_devicetype;
        private uint m_deviceindex;
        private uint m_canid;
        private Timer recvtimer;
        VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[1000];

        //3.定义初始化CAN的数据类型
        public struct VCI_INIT_CONFIG
        {
            public UInt32 AccCode;
            public UInt32 AccMask;
            public UInt32 Reserved;
            public byte Filter;   //0或1接收所有帧。2标准帧滤波，3是扩展帧滤波。
            public byte Timing0;  //波特率参数，具体配置，请查看二次开发库函数说明书。
            public byte Timing1;
            public byte Mode;     //模式，0表示正常模式，1表示只听模式,2自测模式
        }

        public struct VCI_BOARD_INFO
        {
            public UInt16 hw_Version;
            public UInt16 fw_Version;
            public UInt16 dr_Version;
            public UInt16 in_Version;
            public UInt16 irq_Num;
            public byte can_Num;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] str_Serial_Num;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
            public byte[] str_hw_Type;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] Reserved;
        }

        /*------------其他数据结构描述---------------------------------*/
        //4.USB-CAN总线适配器板卡信息的数据类型1，该类型为VCI_FindUsbDevice函数的返回参数。
        public struct VCI_BOARD_INFO1
        {
            public UInt16 hw_Version;
            public UInt16 fw_Version;
            public UInt16 dr_Version;
            public UInt16 in_Version;
            public UInt16 irq_Num;
            public byte can_Num;
            public byte Reserved;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] str_Serial_Num;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] str_hw_Type;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] str_Usb_Serial;
        }

        /*------------数据结构描述完成---------------------------------*/

        public struct CHGDESIPANDPORT
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
            public byte[] szpwd;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] szdesip;
            public Int32 desport;

            public void Init()
            {
                szpwd = new byte[10];
                szdesip = new byte[20];
            }
        }

        public struct VCI_CAN_OBJ  //使用不安全代码
        {
            public uint ID;
            public uint TimeStamp;        //时间标识
            public byte TimeFlag;         //是否使用时间标识
            public byte SendType;         //发送标志。保留，未用
            public byte RemoteFlag;       //是否是远程帧
            public byte ExternFlag;       //是否是扩展帧
            public byte DataLen;          //数据长度

            
            public byte Data0;    //数据
            public byte Data1;    //数据
            public byte Data2;    //数据
            public byte Data3;    //数据
            public byte Data4;    //数据
            public byte Data5;    //数据
            public byte Data6;    //数据
            public byte Data7;    //数据
            
            public byte Reserved0;//保留位
            public byte Reserved1;//保留位
            public byte Reserved2;//保留位
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="Reserved"></param>
        /// <returns></returns>
        /*------------兼容ZLG的函数描述---------------------------------*/
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_Transmit(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);

        /*------------其他函数描述---------------------------------*/

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ConnectDevice(UInt32 DevType, UInt32 DevIndex);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType, UInt32 DevIndex, UInt32 Reserved);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
        public Form1()
        {
            InitializeComponent();
            m_cb_CANType.SelectedIndex = 1;
            m_cb_CANIndex.SelectedIndex = 0;
            m_cb_CANAB.SelectedIndex = 0;
            comboBox_Filter.SelectedIndex = 0;
            comboBox_Mode.SelectedIndex = 0;



            if(!File.Exists(System.Environment.CurrentDirectory + "\\ControlCAN.dll"))
            {
                var fs=File.Create(System.Environment.CurrentDirectory + "\\ControlCAN.dll");
                fs.Write(CANHelper.Properties.Resources.ControlCAN,0, CANHelper.Properties.Resources.ControlCAN.Length);
                fs.Flush();
                fs.Close();
            }

            dataSend = (byte[] data) => {
                if (!isOpen) return;
                VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
                //sendobj.Init();
                sendobj.RemoteFlag = (byte)0;
                sendobj.ExternFlag = (byte)1;
                sendobj.ID = (uint)(data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24));
                sendobj.DataLen = 8;
                
                sendobj.Data0 = data[0];
                sendobj.Data1 = data[1];
                sendobj.Data2 = data[2];
                sendobj.Data3 = data[3];
                sendobj.Data4 = data[4];
                sendobj.Data5 = data[5];
                sendobj.Data6 = data[6];
                sendobj.Data7 = data[7];

                if (VCI_Transmit(m_devicetype, m_deviceindex, m_canid, ref sendobj, 1) == 0)
                {
                    
                    if(isOpen)
                    {
                        m_b_canstart_Click(null, null);
                    }
                    MessageBox.Show("发送失败", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            };

            dataRecv = (List<byte[]> info) => {
                dataBuff = info;
            };
            int[] timedata = { 0x0014,0x0016,0x80b6,0x001c,0x80fa,0x011c,0x81fa,0x031c,0x041c,0x83ff,0x091c,0x87ff,0x181c,0x311c };
            List<int> canbps = new List<int>(new int[]{ 1000, 800, 666, 500, 400, 250, 200, 125, 100, 80, 50, 40, 20, 10 });
            SetBPS = (int value) =>
              {
                  int index = canbps.IndexOf(value);
                  if (index != -1)
                  {
                      textBox_Time0.Text = string.Format("{0:X2}", timedata[index] >> 8);
                      textBox_Time1.Text = string.Format("{0:X2}", timedata[index] &0xff);
                  }
              };

            Close=()=>{
                if (isOpen)
                    m_b_canstart_Click(null, null);
            };

            recvtimer = new Timer();
            recvtimer.Enabled = false;
            recvtimer.Interval = 1;
            recvtimer.Tick += (object s,EventArgs e) => {
                var res = VCI_Receive(m_devicetype, m_deviceindex, m_canid, ref m_recobj[0], 1000, 1);
                if (res >= 1000) return;
                if (res == 0) return;
                for(int i=0;i< res; i++)
                {
                    var data = new byte[12];
                    var info = m_recobj[i];
                    
                    data[0] = info.Data0;
                    data[1] = info.Data1;
                    data[2] = info.Data2;
                    data[3] = info.Data3;
                    data[4] = info.Data4;
                    data[5] = info.Data5;
                    data[6] = info.Data6;
                    data[7] = info.Data7;

                    data[8] = (byte)(info.ID & 0xff);
                    data[9] = (byte)((info.ID >> 8) & 0xff);
                    data[10] = (byte)((info.ID >> 16) & 0xff);
                    data[11] = (byte)((info.ID >> 24) & 0xff);

                    dataBuff.Add(data);
                }
                //if ((isOpen==false) && (closebutton.DialogResult != DialogResult.Cancel))
                //{
                //    isOpen = true;
                //    m_b_canstart_Click(null, null);
                //}
            };
            recvtimer.Start();
        }

        List<byte[]> dataBuff = new List<byte[]>();

        public Action<List<byte[]>> dataRecv;
        public Action<byte[]> dataSend;
        public Action<int> SetBPS;
        public Action Close;

        private void Form1_Load(object sender, EventArgs e)
        {
            //var info = new VCI_BOARD_INFO1();
            //var num=VCI_FindUsbDevice(ref info);
        }

        private void closebutton_Click(object sender, EventArgs e)
        {

        }

        private void m_b_canstart_Click(object sender, EventArgs e)
        {
            if (isOpen)
            {
                VCI_CloseDevice(m_devicetype, m_deviceindex);
                isOpen = false;
                closebutton.DialogResult = DialogResult.Cancel;
            }
            else
            {
                m_devicetype = (uint)(m_cb_CANType.SelectedIndex==0?3:4);
                m_deviceindex = (uint)(m_cb_CANAB.SelectedIndex);
                m_canid = (uint)(m_cb_CANAB.SelectedIndex);
                if(VCI_ConnectDevice(m_devicetype, m_deviceindex) == 0)
                {
                    MessageBox.Show(string.Format("打开{0}号设备失败", m_deviceindex), "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
                if (VCI_OpenDevice(m_devicetype,m_deviceindex,0)==0)
                {
                    MessageBox.Show("打开设备失败,请检查设备类型和设备索引号是否正确", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
                VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
                config.AccCode = System.Convert.ToUInt32("0x" + textBox_AccCode.Text, 16);
                config.AccMask = System.Convert.ToUInt32("0x" + textBox_AccMask.Text, 16);
                config.Timing0 = System.Convert.ToByte("0x" + textBox_Time0.Text, 16);
                config.Timing1 = System.Convert.ToByte("0x" + textBox_Time1.Text, 16);
                config.Filter = (Byte)(comboBox_Filter.SelectedIndex + 1);
                config.Mode = (Byte)comboBox_Mode.SelectedIndex;
                VCI_InitCAN(m_devicetype, m_deviceindex, m_canid, ref config);
                VCI_ResetCAN(m_devicetype, m_deviceindex, m_canid);
                VCI_StartCAN(m_devicetype, m_deviceindex, m_canid);
                isOpen = true;
                closebutton.DialogResult = DialogResult.OK;
            }
            m_b_canstart.Text = isOpen ? "断开" : "连接CAN";
            recvtimer.Enabled = isOpen;
        }

        private void m_b_cantest_Click(object sender, EventArgs e)
        {
            dataSend(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, });
        }
    }
}
